﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using DDW;

namespace SD007
{
    public class SD007Visitor : AbstractVisitor
    {
        
        public override object VisitAccessorNode(AccessorNode accessorNode, object data)
        {
            return base.VisitAccessorNode(accessorNode, data);
        }

        public override object VisitAddressOfExpression(AddressOfExpression addressOfExpression, object data)
        {
            return base.VisitAddressOfExpression(addressOfExpression, data);
        }

        public override object VisitAddressOutNode(OutNode outNode, object data)
        {
            return base.VisitAddressOutNode(outNode, data);
        }

        public override object VisitAnonymousMethodExpression(AnonymousMethodNode anonymousMethodExpression, object data)
        {
            return base.VisitAnonymousMethodExpression(anonymousMethodExpression, data);
        }

        public override object VisitArgumentNode(ArgumentNode argumentNode, object data)
        {
            return base.VisitArgumentNode(argumentNode, data);
        }

        public override object VisitArrayCreateExpression(ArrayCreationExpression arrayCreateExpression, object data)
        {
            return base.VisitArrayCreateExpression(arrayCreateExpression, data);
        }

        public override object VisitArrayInitializerExpression(ArrayInitializerExpression arrayInitializerExpression, object data)
        {
            return base.VisitArrayInitializerExpression(arrayInitializerExpression, data);
        }

        public override object VisitAssignmentExpression(AssignmentExpression assignmentExpression, object data)
        {
            return base.VisitAssignmentExpression(assignmentExpression, data);
        }

        public override object VisitAttribute(AttributeNode attribute, object data)
        {
            return base.VisitAttribute(attribute, data);
        }

        public override object VisitAttributeArgumentNode(AttributeArgumentNode attributeArgumentNode, object data)
        {
            return base.VisitAttributeArgumentNode(attributeArgumentNode, data);
        }

        public override object VisitBaseReferenceExpression(BaseAccessExpression baseAccessExpression, object data)
        {
            data = true;
            return base.VisitBaseReferenceExpression(baseAccessExpression, data);
        }

        public override object VisitBinaryOperatorExpression(BinaryExpression binaryOperatorExpression, object data)
        {
            return base.VisitBinaryOperatorExpression(binaryOperatorExpression, data);
        }

        public override object VisitBlockStatement(BlockStatement blockStatement, object data)
        {
            return base.VisitBlockStatement(blockStatement, data);
        }

        public override object VisitBooleanPrimitive(BooleanPrimitive booleanPrimitive, object data)
        {
            return base.VisitBooleanPrimitive(booleanPrimitive, data);
        }

        public override object VisitBreakStatement(BreakStatement breakStatement, object data)
        {
            return base.VisitBreakStatement(breakStatement, data);
        }

        public override object VisitCastExpression(UnaryCastExpression castExpression, object data)
        {
            return base.VisitCastExpression(castExpression, data);
        }

        public override object VisitCatchClause(CatchNode catchClause, object data)
        {
            return base.VisitCatchClause(catchClause, data);
        }

        public override object VisitCharPrimitive(CharPrimitive charPrimitive, object data)
        {
            return base.VisitCharPrimitive(charPrimitive, data);
        }


        public override object VisitCheckedExpression(CheckedExpression checkedExpression, object data)
        {
            return base.VisitCheckedExpression(checkedExpression, data);
        }

        public override object VisitCheckedStatement(CheckedStatement checkedStatement, object data)
        {
            return base.VisitCheckedStatement(checkedStatement, data);
        }

        public override object VisitClassDeclaration(ClassNode classDeclaration, object data)
        {
            return base.VisitClassDeclaration(classDeclaration, data);
        }

        public override object VisitCommentStatement(CommentStatement commentStatement, object data)
        {
            return base.VisitCommentStatement(commentStatement, data);
        }

        public override object VisitCompilationUnit(CompilationUnitNode compilationUnit, object data)
        {
            return base.VisitCompilationUnit(compilationUnit, data);
        }

        public override object VisitConditionalExpression(ConditionalExpression conditionalExpression, object data)
        {
            return base.VisitConditionalExpression(conditionalExpression, data);
        }

        public override object VisitConstantExpressions(ConstantExpression constantExpression, object data)
        {
            return base.VisitConstantExpressions(constantExpression, data);
        }

        public override object VisitConstantNode(ConstantNode constantNode, object data)
        {
            return base.VisitConstantNode(constantNode, data);
        }

        public override object VisitConstraintExpression(ConstraintExpressionNode constraintExpression, object data)
        {
            return base.VisitConstraintExpression(constraintExpression, data);
        }

        public override object VisitConstructorConstraint(ConstructorConstraint constructorConstraint, object data)
        {
            return base.VisitConstructorConstraint(constructorConstraint, data);
        }

        public override object VisitConstructorDeclaration(ConstructorNode constructorDeclaration, object data)
        {
            return base.VisitConstructorDeclaration(constructorDeclaration, data);
        }

        public override object VisitContinueStatement(ContinueStatement continueStatement, object data)
        {
            return base.VisitContinueStatement(continueStatement, data);
        }

        public override object VisitDecimalPrimitive(DecimalPrimitive decimalPrimitive, object data)
        {
            return base.VisitDecimalPrimitive(decimalPrimitive, data);
        }

        public override object VisitDeclarator(Declarator declarator, object data)
        {
            return base.VisitDeclarator(declarator, data);
        }

        public override object VisitDefaultValueExpression(DefaultConstantExpression defaultConstantExpression, object data)
        {
            return base.VisitDefaultValueExpression(defaultConstantExpression, data);
        }

        public override object VisitDelegateDeclaration(DelegateNode delegateDeclaration, object data)
        {
            return base.VisitDelegateDeclaration(delegateDeclaration, data);
        }

        public override object VisitDereferenceExpression(DereferenceExpression dereferenceExpression, object data)
        {
            return base.VisitDereferenceExpression(dereferenceExpression, data);
        }

        public override object VisitDestructorDeclaration(DestructorNode destructorDeclaration, object data)
        {
            return base.VisitDestructorDeclaration(destructorDeclaration, data);
        }

        public override object VisitDoLoopStatement(DoStatement doLoopStatement, object data)
        {
            return base.VisitDoLoopStatement(doLoopStatement, data);
        }

        public override object VisitElementAccessExpression(ElementAccessExpression elementAccessExpression, object data)
        {
            return base.VisitElementAccessExpression(elementAccessExpression, data);
        }

        public override object VisitEnumDeclaration(EnumNode enumDeclaration, object data)
        {
            return base.VisitEnumDeclaration(enumDeclaration, data);
        }

        public override object VisitEventDeclaration(EventNode eventDeclaration, object data)
        {
            return base.VisitEventDeclaration(eventDeclaration, data);
        }

        public override object VisitExpressionStatement(ExpressionStatement expressionStatement, object data)
        {
            return base.VisitExpressionStatement(expressionStatement, data);
        }

        public override object VisitExternAliasDirectiveNode(ExternAliasDirectiveNode externAliasDirectiveNode, object data)
        {
            return base.VisitExternAliasDirectiveNode(externAliasDirectiveNode, data);
        }

        public override object VisitFieldDeclaration(FieldNode fieldDeclaration, object data)
        {
            return base.VisitFieldDeclaration(fieldDeclaration, data);
        }

        public override object VisitFinallyStatement(FinallyNode finallyStatement, object data)
        {
            return base.VisitFinallyStatement(finallyStatement, data);
        }

        public override object VisitFixedBufferNode(FixedBufferNode fixedBufferNode, object data)
        {
            return base.VisitFixedBufferNode(fixedBufferNode, data);
        }

        public override object VisitFixedDeclarationStatement(FixedDeclarationsStatement fixedDeclarationsStatement, object data)
        {
            return base.VisitFixedDeclarationStatement(fixedDeclarationsStatement, data);
        }

        public override object VisitFixedStatement(FixedStatementStatement fixedStatement, object data)
        {
            return base.VisitFixedStatement(fixedStatement, data);
        }

        public override object VisitForeachStatement(ForEachStatement foreachStatement, object data)
        {
            var iterator = foreachStatement.Iterator;
            StringBuilder typeName = new StringBuilder();
            iterator.Type.ToSource(typeName);
            this.localVariables.Add(new VariableAbstraction(iterator.Name, typeName.ToString()));

            return base.VisitForeachStatement(foreachStatement, data);
        }

        public override object VisitGenericConstraint(Constraint genericConstraint, object data)
        {
            return base.VisitGenericConstraint(genericConstraint, data);
        }

        public override object VisitGenericDefinition(GenericNode genericNode, object data)
        {
            return base.VisitGenericDefinition(genericNode, data);
        }

        public override object VisitGotoStatement(GotoStatement gotoStatement, object data)
        {
            return base.VisitGotoStatement(gotoStatement, data);
        }

        public override object VisitIdentifierExpression(IdentifierExpression identifierExpression, object data)
        {
            if (data == null || !(bool)data)
            {
                data = null;
                this.AddVariableAccessed(new VariableAbstraction(identifierExpression.Identifier, ""));
            }
            return base.VisitIdentifierExpression(identifierExpression, data);
        }
                
        public override object VisitIndexerDeclaration(IndexerNode indexerDeclaration, object data)
        {
            return base.VisitIndexerDeclaration(indexerDeclaration, data);
        }

        public override object VisitIntegralPrimitive(IntegralPrimitive integralPrimitive, object data)
        {
            return base.VisitIntegralPrimitive(integralPrimitive, data);
        }

        public override object VisitInterfaceDeclaration(InterfaceNode interfaceDeclaration, object data)
        {
            return base.VisitInterfaceDeclaration(interfaceDeclaration, data);
        }

        public override object VisitInterfaceEventNode(InterfaceEventNode interfaceEventNode, object data)
        {
            return base.VisitInterfaceEventNode(interfaceEventNode, data);
        }

        public override object VisitInterfaceIndexerNode(InterfaceIndexerNode interfaceIndexerNode, object data)
        {
            return base.VisitInterfaceIndexerNode(interfaceIndexerNode, data);
        }

        public override object VisitInterfaceMethodNode(InterfaceMethodNode interfaceMethodNode, object data)
        {
            return base.VisitInterfaceMethodNode(interfaceMethodNode, data);
        }

        public override object VisitInterfacePropertyNode(InterfacePropertyNode interfacePropertyNode, object data)
        {
            return base.VisitInterfacePropertyNode(interfacePropertyNode, data);
        }

        public override object VisitInvocationExpression(InvocationExpression invocationExpression, object data)
        {
            data = true;
            return base.VisitInvocationExpression(invocationExpression, data);
        }

        public override object VisitLabelStatement(LabeledStatement labelStatement, object data)
        {
            return base.VisitLabelStatement(labelStatement, data);
        }

        public override object VisitLocalDeclaration(LocalDeclaration localDeclaration, object data)
        {
            return base.VisitLocalDeclaration(localDeclaration, data);
        }

        public override object VisitLocalDeclarationStatement(LocalDeclarationStatement localVariableDeclaration, object data)
        {
            StringBuilder typeNameGetter = new StringBuilder();
            IType t = localVariableDeclaration.Type;
            t.ToSource(typeNameGetter);
            string typeName = typeNameGetter.ToString();
            foreach (var declarator in localVariableDeclaration.Declarators)
                this.AddLocalVariable(new VariableAbstraction(declarator.Identifier.Identifier, typeName));
            return base.VisitLocalDeclarationStatement(localVariableDeclaration, data);
        }

        public override object VisitLockStatement(LockStatement lockStatement, object data)
        {
            return base.VisitLockStatement(lockStatement, data);
        }

        public override object VisitMemberAccessExpression(MemberAccessExpression memberAccessExpression, object data)
        {
            data = true;
            if (memberAccessExpression.Left is IdentifierExpression)
            {
                string id = ((IdentifierExpression)memberAccessExpression.Left).Identifier;
                if (id != "this" && id != "base")
                    this.AddVariableAccessed(new VariableAbstraction(id, ""));
            }
            return base.VisitMemberAccessExpression(memberAccessExpression, data);
        }

        public override object VisitMethodDeclaration(MethodNode methodDeclaration, object data)
        {
            return base.VisitMethodDeclaration(methodDeclaration, data);
        }

        public override object VisitNamespaceDeclaration(NamespaceNode namespaceDeclaration, object data)
        {
            return base.VisitNamespaceDeclaration(namespaceDeclaration, data);
        }

        public override object VisitNullPrimitive(NullPrimitive nullPrimitive, object data)
        {
            return base.VisitNullPrimitive(nullPrimitive, data);
        }

        public override object VisitObjectCreateExpression(ObjectCreationExpression objectCreateExpression, object data)
        {
            return base.VisitObjectCreateExpression(objectCreateExpression, data);
        }

        public override object VisitOperatorDeclaration(OperatorNode operatorDeclaration, object data)
        {
            return base.VisitOperatorDeclaration(operatorDeclaration, data);
        }

        public override object VisitParameterDeclarationExpression(ParamDeclNode parameterDeclarationExpression, object data)
        {
            return base.VisitParameterDeclarationExpression(parameterDeclarationExpression, data);
        }

        public override object VisitParenthesizedExpression(ParenthesizedExpression parenthesizedExpression, object data)
        {
            return base.VisitParenthesizedExpression(parenthesizedExpression, data);
        }

        public override object VisitPostDecrementExpression(PostDecrementExpression postDecrementExpression, object data)
        {
            return base.VisitPostDecrementExpression(postDecrementExpression, data);
        }

        public override object VisitPostIncrementExpression(PostIncrementExpression postIncrementExpression, object data)
        {
            return base.VisitPostIncrementExpression(postIncrementExpression, data);
        }

        public override object VisitPredefinedTypeReference(PredefinedTypeNode predefinedTypeNode, object data)
        {
            return base.VisitPredefinedTypeReference(predefinedTypeNode, data);
        }

        public override object VisitPrimaryExpression(PrimaryExpression primitiveExpression, object data)
        {
            return base.VisitPrimaryExpression(primitiveExpression, data);
        }

        public override object VisitPropertyDeclaration(PropertyNode propertyDeclaration, object data)
        {
            return base.VisitPropertyDeclaration(propertyDeclaration, data);
        }

        public override object VisitQualifiedIdentifierExpression(QualifiedIdentifierExpression qualifiedIdentifierExpression, object data)
        {
            data = true;
            return base.VisitQualifiedIdentifierExpression(qualifiedIdentifierExpression, data);
        }

        public override object VisitRealPrimitive(RealPrimitive realPrimitive, object data)
        {
            return base.VisitRealPrimitive(realPrimitive, data);
        }

        public override object VisitRefNode(RefNode refNode, object data)
        {
            return base.VisitRefNode(refNode, data);
        }

        public override object VisitReturnStatement(ReturnStatement returnStatement, object data)
        {
            return base.VisitReturnStatement(returnStatement, data);
        }

        public override object VisitSizeOfExpression(SizeOfExpression sizeOfExpression, object data)
        {
            return base.VisitSizeOfExpression(sizeOfExpression, data);
        }

        public override object VisitStackAllocExpression(StackallocExpression stackAllocExpression, object data)
        {
            return base.VisitStackAllocExpression(stackAllocExpression, data);
        }

        public override object VisitStatementNode(StatementNode statementNode, object data)
        {
            return base.VisitStatementNode(statementNode, data);
        }

        public override object VisitStringPrimitive(StringPrimitive stringPrimitive, object data)
        {
            return base.VisitStringPrimitive(stringPrimitive, data);
        }

        public override object VisitStructNode(StructNode structNode, object data)
        {
            return base.VisitStructNode(structNode, data);
        }

        public override object VisitSwitchStatement(SwitchStatement switchStatement, object data)
        {
            return base.VisitSwitchStatement(switchStatement, data);
        }

        public override object VisitThisReferenceExpression(ThisAccessExpression thisReferenceExpression, object data)
        {
            data = true;
            return base.VisitThisReferenceExpression(thisReferenceExpression, data);
        }

        public override object VisitThrowStatement(ThrowNode throwStatement, object data)
        {
            return base.VisitThrowStatement(throwStatement, data);
        }

        public override object VisitTryStatement(TryStatement tryStatement, object data)
        {
            return base.VisitTryStatement(tryStatement, data);
        }

        public override object VisitTypeOfExpression(TypeOfExpression typeOfExpression, object data)
        {
            return base.VisitTypeOfExpression(typeOfExpression, data);
        }

        public override object VisitTypeParameter(TypeParameterNode typeParameter, object data)
        {
            return base.VisitTypeParameter(typeParameter, data);
        }

        public override object VisitTypePointerReference(TypePointerNode typePointerReference, object data)
        {
            return base.VisitTypePointerReference(typePointerReference, data);
        }

        public override object VisitTypeReference(TypeNode typeReference, object data)
        {
            return base.VisitTypeReference(typeReference, data);
        }

        public override object VisitUnaryExpression(UnaryExpression unaryExpression, object data)
        {
            return base.VisitUnaryExpression(unaryExpression, data);
        }

        public override object VisitUncheckedExpression(UncheckedExpression uncheckedExpression, object data)
        {
            return base.VisitUncheckedExpression(uncheckedExpression, data);
        }

        public override object VisitUncheckedStatement(UncheckedStatement uncheckedStatement, object data)
        {
            return base.VisitUncheckedStatement(uncheckedStatement, data);
        }

        public override object VisitUsingDirective(UsingDirectiveNode @using, object data)
        {
            return base.VisitUsingDirective(@using, data);
        }

        public override object VisitUsingStatement(UsingStatement usingDeclaration, object data)
        {
            return base.VisitUsingStatement(usingDeclaration, data);
        }

        public override object VisitVoidPrimitive(VoidPrimitive voidPrimitive, object data)
        {
            return base.VisitVoidPrimitive(voidPrimitive, data);
        }
        
        public override object VisitYieldStatement(YieldStatement yieldStatement, object data)
        {
            return base.VisitYieldStatement(yieldStatement, data);
        }

        public override object VisitIfStatement(IfStatement ifStatement, object data)
        {
            this.QtdIf++;
            return base.VisitIfStatement(ifStatement, data);
        }
        
        public override object VisitCaseLabel(CaseNode caseLabel, object data)
        {
            this.QtdCase++;
            return base.VisitCaseLabel(caseLabel, data);
        }

        public override object VisitWhileStatement(WhileStatement whileStatement, object data)
        {
            this.QtdWhile++;
            return base.VisitWhileStatement(whileStatement, data);
        }

        public override object VisitForStatement(ForStatement forStatement, object data)
        {
            this.QtdFor++;            
            return base.VisitForStatement(forStatement, data);
        }

        public void AddVariableAccessed(VariableAbstraction variable)
        {
            if (!this.variablesAccessed.Contains(variable))
                this.variablesAccessed.Add(variable);
        }

        public void AddLocalVariable(VariableAbstraction variable)
        {
            if (!this.localVariables.Contains(variable))
                this.localVariables.Add(variable);
        }

        public List<VariableAbstraction> variablesAccessed = new List<VariableAbstraction>();
        //public List<string> localVariables = new List<string>();
        public List<VariableAbstraction> localVariables = new List<VariableAbstraction>();

        private int qtdIf;

        public int QtdIf
        {
            get { return qtdIf; }
            set { qtdIf = value; }
        }

        private int qtdCase;

        public int QtdCase
        {
            get { return qtdCase; }
            set { qtdCase = value; }
        }

        private int qtdWhile;

        public int QtdWhile
        {
            get { return qtdWhile; }
            set { qtdWhile = value; }
        }

        private int qtdFor;

        public int QtdFor
        {
            get { return qtdFor; }
            set { qtdFor = value; }
        }


    }
}
